package com.yizhuoyan.idea.ucc;

public class UnicodeChineseDecoder {

	private static final char MAX=UnicodeChineseEncoder.REMAINDER6_LAST_CHAR;

	/**
	 * 14
	 * 56=8x7 14x4
	 */
	public static byte[] decode(char[] src) {
		if(src==null||src.length==0){
			return new byte[0];
		}
		int len = outLength(src);          // dst array size
		byte[] dst = new byte[len];
		int ret = decode0(src, dst);
		return dst;
	}
	private static int outLength(char[] src) {
		int left = src.length%4;
		int len = (src.length/4)*7;
		switch (left){
			case 0:
				if(src[src.length-1]>=MAX){
					return len-1;
				}
				return len;
			case 1:
				return len+1;
			case 2:
				if(((src[src.length-1] - 0x4E00)&1)==0) {
					return len + 2;
				}
				return len+3;
			case 3:
				if(((src[src.length-1] - 0x4E00)&1)==0) {
					return len + 4;
				}
				return len+5;
		}
		throw new UnknownError();
	}
	private static int decode0(char[] src, byte[] dst) {
		int left = src.length%4;
		int i = 0, j = 0;
		if(left==0){
			//可能是(14+14+14+6)48 =6x8
			if(src[src.length-1]>=MAX){
				for (int stop=src.length-4;i < stop;i+=4,j+=7) {
					decodeBlock(src,i,dst,j);
				}
				long bits=((src[i++]-0x4E00L)&0x3fffL)<<34
						|((src[i++]-0x4E00L)&0x3fffL)<<20
						|((src[i++]-0x4E00L)&0x3fffL)<<6
						|((src[i]-MAX)&0x3fL);
				dst[j++]=(byte) (bits>>40);
				dst[j++]=(byte) (bits>>32);
				dst[j++]=(byte) (bits>>24);
				dst[j++]=(byte) (bits>>16);
				dst[j++]=(byte) (bits>>8);
				dst[j++]=(byte) (bits);
			}else {
				for (int stop = src.length;i < stop;i+=4,j+=7) {
					decodeBlock(src,i,dst,j);
				}
			}
			return j;
		}
		for (int stop = src.length-left;i < stop;i+=4,j+=7) {
			decodeBlock(src,i,dst,j);
		}
		switch (left){
			case 1: //8
				//000-000 00 xxxxxxxx
				dst[j++]=(byte)((src[i]-0x4E00)&0xff);
				break;
			case 2: //16/24
			{
				int a = (src[i++] - 0x4E00) & 0x3fff; //14(14/14)
				int b = (src[i] - 0x4E00) & 0x3fff; //14(2/10)
				dst[j++] = (byte) (a >> 6); //a8
				if ((b & 1) == 0) {
					//??0-00 00 000000xx0
					dst[j++] = (byte) (((a & 0x3f) << 2) | ((b >> 1) & 0x3));//a6+b2
				} else {
					//??0-0-0xxx xxxxxxx1
					dst[j++] = (byte) (((a & 0x3f) << 2) | ((b >> 9) & 0x3));//a6+b2
					dst[j++] = (byte) (b >> 1);//b8
				}
				break;
			}
			case 3: //32/40
			{
				int a = (src[i++] - 0x4E00) & 0x3fff; //14(14/14)
				int b = (src[i++] - 0x4E00) & 0x3fff; //14(14/14)
				int c = (src[i] - 0x4E00) & 0x3fff; //14(4/12)
				dst[j++] = (byte) ((a >> 6)); //a8
				dst[j++] = (byte) (((a & 0x3f) << 2) | ((b>>12) & 0x3));//a6+b2
				dst[j++] = (byte) (b >> 4);//b8
				if ((c & 1) == 0) {
					//??0-00-000 000xxxx0
					dst[j++] = (byte) (((b & 0xf) << 4) | ((c >> 1) & 0xf));//b4+c4
				} else {
					//??0-x-xxxx xxxxxxx1
					dst[j++] = (byte) (((b & 0xf) << 4) | ((c >> 9) & 0xf));//b4+c4
					dst[j++] = (byte) (c>>1);//c8
				}
				break;
			}
		}


		return j;
	}

	private static void decodeBlock(char[] src, int i, byte[] dst, int j) {
		long bits=((src[i++]-0x4E00L)&0x3fffL)<<42
				|((src[i++]-0x4E00L)&0x3fffL)<<28
				|((src[i++]-0x4E00L)&0x3fffL)<<14
				|((src[i]-0x4E00L)&0x3fffL);
		dst[j++]=(byte) (bits>>48);
		dst[j++]=(byte) (bits>>40);
		dst[j++]=(byte) (bits>>32);
		dst[j++]=(byte) (bits>>24);
		dst[j++]=(byte) (bits>>16);
		dst[j++]=(byte) (bits>>8);
		dst[j]=(byte) (bits);
	}


}
